﻿using System;
using System.Collections.Generic;
using ChibiTD.Common;
using ChibiTD.Common.Enums;
using ChibiTD.Core.Interfaces;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;

namespace ChibiTD.Core.Objects
{
    public abstract class Entity : IEntity
    {
        protected Game mGame;
        protected int mWidth;
        protected int mHeight;
        protected Texture2D mTexture;
        protected Vector2 mPosition;
        protected Dictionary<AnimationState, Animation> mAnimations;
        protected AnimationState mCurrentAnimation;
        protected bool mLoopAnimation;
        protected float mRotation;
        protected float mSpeed;
        protected MovementState mMovementState;
        
        protected Entity(Game game, int width, int height, Vector2 position)
        {
            this.mGame = game;
            this.mWidth = width;
            this.mHeight = height;
            this.mRotation = 0f;
            this.mSpeed = 0f;
            this.mPosition = position;
            this.mAnimations = new Dictionary<AnimationState, Animation>();
            this.mCurrentAnimation = AnimationState.Stopped;
            this.mLoopAnimation = true;
            this.mMovementState = MovementState.Stopped;
        }

        public Game Game
        {
            get { return mGame; }
            set { mGame = value; }
        }

        public int Width
        {
            get { return mWidth; }
            set { mWidth = value; }
        }

        public int Height
        {
            get { return mHeight; }
            set { mHeight = value; }
        }

        public Texture2D Texture
        {
            get { return mTexture; }
            set { mTexture = value; }
        }

        public Vector2 Position
        {
            get { return mPosition; }
            set { mPosition = value; }
        }

        public Dictionary<AnimationState, Animation> Animations
        {
            get { return mAnimations; }
            set { mAnimations = value; }
        }

        public AnimationState CurrentAnimation
        {
            //get is easy. just return the value.
            get { return mCurrentAnimation; }

            //set is a little more advanced...
            set
            {
                //if the value passed in is not a key in our dictionary, we can't use it
                //so we will throw an exception.
                if (!Animations.ContainsKey(value))
                    throw new Exception("Invalid animation specified.");

                //we only want to change animations if the currentAnimation is unset (null)
                //or if the new value is different than the currentAnimation.
                if (mCurrentAnimation == null || !mCurrentAnimation.Equals(value))
                {
                    //set the current animation
                    mCurrentAnimation = value;

                    //reset the animation
                    Animations[mCurrentAnimation].Reset();
                }
            }
        }

        public bool LoopAnimation
        {
            get { return mLoopAnimation; }
            set { mLoopAnimation = value; }
        }

        public float Speed
        {
            get { return mSpeed; }
            set { mSpeed = value; }
        }

        public float Rotation
        {
            get { return mRotation; }
            set { mRotation = value; }
        }

        public MovementState MovementState
        {
            get { return mMovementState; }
            set { mMovementState = value; }
        }

        public void UpdateAnimation(GameTime gameTime)
        {
            //here we have to make sure we have a valid animation to use if
            //nobody has yet set the currentAnimation.
            if (mCurrentAnimation == null)
            {
                //if there are no keys, we don't have any animations so we just quit
                if (Animations.Keys.Count == 0)
                    return;

                //get a list of the valid Keys in the Animations dictionary.
                AnimationState[] keys = new AnimationState[Animations.Keys.Count];

                //copy the keys out of the dictionary to the array
                Animations.Keys.CopyTo(keys, 0);

                //set the currentAnimation to the first animation
                mCurrentAnimation = keys[0];
            }

            //if we are updating the animation, call its Update method
            if (mLoopAnimation)
                Animations[mCurrentAnimation].Update(gameTime);
        }

        public abstract void LoadTexture(string texture);
        public abstract void Draw(SpriteBatch batch);
    }
}
